package de.nonspectare.utils;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.eclipse.persistence.internal.oxm.record.XMLReader;
import org.eclipse.persistence.sessions.factories.XMLProjectReader;
import org.jdom.Element;
import org.jdom.Document;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

public class XMLPreparation {

	private File file;

	// private String name;
	// private String location;

	// public String getName() {
	// return name;
	// }
	//
	// public void setName(String name) {
	// this.name = name;
	// }
	//
	// public String getLocation() {
	// return location;
	// }
	//
	// public void setLocation(String location) {
	// this.location = location;
	// }

	public XMLPreparation() {
	}

	public static File saveFile(String path, String newPath) {

		// Herunterladen und im Projektordner speichern

		return URLFileSaver.saveXML(path, newPath);
		// this.file = new File(System.getProperty("user.dir") +
		// System.getProperty("file.separator") + "xmlfile.wsdl");
	}

	public static void replaceAllNamespaces(String path, String namespace) {

		String text = new String();

		try {

			SAXBuilder builder = new SAXBuilder();
			Document doc = (Document) builder.build(new File(path));
			Element rootNode = doc.getRootElement();

			String targetNamespace = rootNode.getAttribute("targetNamespace")
					.getValue();
			System.out.println(targetNamespace);

			BufferedReader br = new BufferedReader(new FileReader(
					new File(path)));

			String line = "";
			while ((line = br.readLine()) != null) {
				text += line + "\r\n";
			}

			br.close();

			String result = text.replaceAll(
					"WebServiceComplexDataTypeNamespace", namespace);

			FileWriter writer = new FileWriter(new File(path));
			writer.write(result);
			writer.flush();
			writer.close();

		} catch (IOException | JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void changeSoapAdress(String soapAddress) {

		Document doc;
		try {

			SAXBuilder builder = new SAXBuilder();
			doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			Element node = rootNode
					.getChild("service", rootNode.getNamespace())
					.getChild("port", rootNode.getNamespace())
					.getChild(
							"address",
							Namespace.getNamespace("soap",
									"http://schemas.xmlsoap.org/wsdl/soap/"));

			node.getAttribute("location").setValue(soapAddress);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (JDOMException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void changeRootAttribute(String attributeName, String changeTo) {

		// http://www.mkyong.com/java/how-to-modify-xml-file-in-java-jdom/
		try {
			SAXBuilder builder = new SAXBuilder();
			Document doc;
			doc = (Document) builder.build(this.file);

			Element rootNode = doc.getRootElement();

			rootNode.getAttribute(attributeName).setValue(changeTo);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (JDOMException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void changeTargetNamespace(String targetNamespace) {

		try {
			// Quelle:
			// http://www.mkyong.com/java/how-to-modify-xml-file-in-java-jdom/
			SAXBuilder builder = new SAXBuilder();
			// File xmlfile = new File(location +
			// System.getProperty("file.separator") + name);

			Document doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			// Element e = rootNode.getChild("xs:schema");
			rootNode.getAttribute("targetNamespace").setValue(targetNamespace);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void changeSchemaLocation(String newSchemaLocation) {

		try {
			// Herunterladen und im Projektordner speichern
			// URLFileSaver.saveXML(file, location +
			// System.getProperty("file.separator") + name);

			// Quelle:
			// http://www.mkyong.com/java/how-to-modify-xml-file-in-java-jdom/
			SAXBuilder builder = new SAXBuilder();
			// File xmlfile = new File(this.location);

			Document doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			Namespace xsdns = Namespace.getNamespace("xsd",
					"http://www.w3.org/2001/XMLSchema");

			Element node = rootNode.getChild("types", rootNode.getNamespace())
					.getChild("schema", xsdns).getChild("import", xsdns);

			node.getAttribute("schemaLocation").setValue(newSchemaLocation);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void changeServiceName(String serviceName) {
		try {

			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			rootNode.getAttribute("name").setValue(serviceName);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void changePortType(String portType) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			Element node = rootNode.getChild("portType",
					rootNode.getNamespace());

			node.getAttribute("name").setValue(portType);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void changeBinding(String portType) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			Element node = rootNode
					.getChild("binding", rootNode.getNamespace());

			node.getAttribute("name").setValue(portType + "Binding");
			node.getAttribute("type").setValue("tns:" + portType);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void changeService(String value) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			Element node = rootNode
					.getChild("service", rootNode.getNamespace());
			node.getAttribute("name").setValue(value + "Service");

			Element port = node.getChild("port", rootNode.getNamespace());
			port.getAttribute("name").setValue(value + "Port");
			port.getAttribute("binding").setValue("tns:" + value + "Binding");

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void changeOperation(String operationName) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(this.file);
			Element rootNode = doc.getRootElement();

			Element node = rootNode.getChild("portType",
					rootNode.getNamespace()).getChild("operation",
					rootNode.getNamespace());
			node.getAttribute("name").setValue(operationName);

			rootNode.getChild("binding", rootNode.getNamespace())
					.getChild("operation", rootNode.getNamespace())
					.getAttribute("name").setValue(operationName);

			FileWriter output = new FileWriter(this.file.getAbsolutePath());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param xsdAddress
	 * @param operationAddress
	 * @param soapAddress
	 */
	public static void changeAddresses(String wsdlPath, String xsdAddress,
			String operationAddress, String soapAddress) {

		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(new File(wsdlPath));
			Element rootNode = doc.getRootElement();

			Element node = rootNode.getChild("types", rootNode.getNamespace());

			node.getChild(
					"schema",
					Namespace.getNamespace("xsd",
							"http://www.w3.org/2001/XMLSchema"))
					.getChild(
							"import",
							Namespace.getNamespace("xsd",
									"http://www.w3.org/2001/XMLSchema"))
					.getAttribute("schemaLocation").setValue(xsdAddress);

			String address = rootNode
					.getChild("service", rootNode.getNamespace())
					.getChild("port", rootNode.getNamespace())
					.getChild(
							"address",
							Namespace.getNamespace("soap",
									"http://schemas.xmlsoap.org/wsdl/soap/"))
					.getAttribute("location").getValue();

			// austausch der Serveradresse
			// finde das dritte "/"
			CharacterIterator it = new StringCharacterIterator(address);

			int pos = 0;
			int begin = 0;
			int end = 0;
			int value = 0;

			// Iterate over the characters in the forward direction
			for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it
					.next()) {
				if (ch == '/') {
					value++;
					if (value == 3) {
						end = pos;

					}
				}
				pos++;
			}

			rootNode.getChild("service", rootNode.getNamespace())
					.getChild("port", rootNode.getNamespace())
					.getChild(
							"address",
							Namespace.getNamespace("soap",
									"http://schemas.xmlsoap.org/wsdl/soap/"))
					.getAttribute("location")
					.setValue(
							address.replaceAll(address.substring(0, end + 1),
									soapAddress));

			FileWriter output = new FileWriter(wsdlPath);

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String getXSDPathFromWSDL(File wsdlFile) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(wsdlFile);
			Element rootNode = doc.getRootElement();

			Element node = rootNode.getChild("types", rootNode.getNamespace());

			return node
					.getChild(
							"schema",
							Namespace.getNamespace("xsd",
									"http://www.w3.org/2001/XMLSchema"))
					.getChild(
							"import",
							Namespace.getNamespace("xsd",
									"http://www.w3.org/2001/XMLSchema"))
					.getAttribute("schemaLocation").getValue();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void setXSDSchemaLocation(File wsdlFile,
			String xsdSchemaLocation) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(wsdlFile);
			Element rootNode = doc.getRootElement();

			Element node = rootNode.getChild("types", rootNode.getNamespace());

			node.getChild(
					"schema",
					Namespace.getNamespace("xsd",
							"http://www.w3.org/2001/XMLSchema"))
					.getChild(
							"import",
							Namespace.getNamespace("xsd",
									"http://www.w3.org/2001/XMLSchema"))
					.getAttribute("schemaLocation").setValue(xsdSchemaLocation);

			FileWriter output = new FileWriter(wsdlFile.getAbsoluteFile());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void setSOAPAddress(File wsdlFile, String targetSOAPAddress) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(wsdlFile);
			Element rootNode = doc.getRootElement();

			Element node = rootNode.getChild("types", rootNode.getNamespace());

			String address = rootNode
					.getChild("service", rootNode.getNamespace())
					.getChild("port", rootNode.getNamespace())
					.getChild(
							"address",
							Namespace.getNamespace("soap",
									"http://schemas.xmlsoap.org/wsdl/soap/"))
					.getAttribute("location").getValue();

			// austausch der Serveradresse
			// finde das dritte "/"
			CharacterIterator it = new StringCharacterIterator(address);

			int pos = 0;
			int begin = 0;
			int end = 0;
			int value = 0;

			// Iterate over the characters in the forward direction
			for (char ch = it.first(); ch != CharacterIterator.DONE; ch = it
					.next()) {
				if (ch == '/') {
					value++;
					if (value == 3) {
						end = pos;

					}
				}
				pos++;
			}

			rootNode.getChild("service", rootNode.getNamespace())
					.getChild("port", rootNode.getNamespace())
					.getChild(
							"address",
							Namespace.getNamespace("soap",
									"http://schemas.xmlsoap.org/wsdl/soap/"))
					.getAttribute("location")
					.setValue(
							address.replaceAll(address.substring(0, end + 1),
									targetSOAPAddress));

			FileWriter output = new FileWriter(wsdlFile.getAbsoluteFile());

			XMLOutputter xmlOutputter = new XMLOutputter();
			xmlOutputter.output(doc, output);

			output.flush();
			output.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String getNodeAttributeName(File xmlFile, String node,
			String child, String attribute) {
		try {
			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(xmlFile);
			Element rootNode = doc.getRootElement();

			Element temp = findTag(rootNode, node);
			Element temp2 = findTag(temp, child);
			String result = temp2.getAttribute(attribute).getValue();

			System.out.println(result);

			return result;

		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	public static Element findTag(Element root, String tag)
			throws IllegalArgumentException {
		if (root == null) {
			throw new IllegalArgumentException("Element is null.");
		}

		List enumChilds = root.getChildren();
		Iterator iter = enumChilds.iterator();

		while (iter.hasNext()) {
			Element childElement = (Element) iter.next();
			if (childElement.getName().equals(tag)) {
				return childElement;
			}
			try {
				Element foundElement = findTag(childElement, tag);
				if (foundElement != null)
					return foundElement;
			} catch (IllegalArgumentException e) {
			}
		}
		return null;
	}
	
	public static Element findTagByAttribute(Element root, String tag, String attribute, String attrVal)
			throws IllegalArgumentException {
		if (root == null) {
			throw new IllegalArgumentException("Element is null.");
		}

		List enumChilds = root.getChildren();
		Iterator iter = enumChilds.iterator();

		while (iter.hasNext()) {
			Element childElement = (Element) iter.next();
			if (childElement.getName().equals(tag)) {
				return childElement;
			}
			try {
				Element foundElement = findTag(childElement, tag);
				if (foundElement != null)
					return foundElement;
			} catch (IllegalArgumentException e) {
			}
		}
		return null;
	}

	public static ArrayList<String> getNodeAttributes(String xmlFile,
			String node, String child, String attribute, String parameter) {

		try {

			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(xmlFile);
			Element rootNode = doc.getRootElement();

			Element temp = findTag(rootNode, node);
			Element temp2 = findTag(temp, child);
			String result = temp2.getAttribute(attribute).getValue();

			System.out.println(result);

			return null;

		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}

	public static String getOperationResponse(String xmlFile, String node, String child,
			String child3, String operationName, String attribute, String xsdFile) {
		
		try {

			SAXBuilder builder = new SAXBuilder();

			Document doc = (Document) builder.build(xmlFile);
			Element rootNode = doc.getRootElement();
			
			Element temp = findTag(rootNode, node);
			
			String output = findTag(temp, child).getAttribute(attribute).getValue();
			
			//Gehe in die XSD-Datei
			Document doc2 = (Document) builder.build(xsdFile);
			
			Element xsdRoot = doc2.getRootElement();

//			List xsdChildren = xsdRoot.getChildren()
			
//			Element temp2 = xsdRoot.getChild("complexType")

			return null;

		} catch (Exception e) {
			e.printStackTrace();
		}

		return null;
	}
}
